// -----------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// *********************************************************************************
// Project Name : 
// Author       : Dark
// Create Time  : 2023-01-30 16:20:28
// Revise Time	: 2023-01-30 16:20:28
// File Name    : dtcm.sv
// Abstract     :
`include "defines.svh"
module dtcm(
	input					clk,    // Clock
	input					rst_n,  // Synchronous reset active low
	input					wren, 
	input					rden, 
	input		  [ 2:0]	mem_ctrl,
	input	      [31:0]	addr,
	input		  [31:0]	din,

	output  logic [31:0]	dout
);
	
	
	
	
//=================================================================================
// Signal declaration
//=================================================================================
	logic	[3:0]	byteena;
	logic			wrclk;
	logic			rdclk;
	logic	[31:0]	wrdata;
	logic	[31:0]	rddata;
	logic	[ 1:0]	addr_byte;

	logic	[ 2:0]	mem_ctrl_pipe;
	logic	[ 1:0]	addr_byte_pipe;	
	
//=================================================================================
// Body
//=================================================================================
	
	// addr low 2 bit 
	assign addr_byte = addr[1:0];
// read ram data need one cycle	
	always_ff @(posedge clk) begin 
		if(~rst_n) begin
			mem_ctrl_pipe	<=	'b0;	
			addr_byte_pipe	<=	'b0;		
		end
		else begin
			mem_ctrl_pipe	<=	mem_ctrl;
			addr_byte_pipe	<=	addr_byte;			
		end
	end
	
	// store byte cs
	always_comb begin
		case (mem_ctrl)
			`MEM_SB	:	byteena = 4'b0001 << addr_byte;
			`MEM_SH	:	byteena = 4'b0011 << addr_byte;
			`MEM_SW	:	byteena = 4'b1111;		
			default : 	byteena = 4'b0000;
		endcase
	end
	// store data generate	
	always_comb begin
		case (mem_ctrl)
			`MEM_SB	:	
				begin
					if (addr_byte == 2'b00)
						wrdata = {24'b0,din[7:0]};
					else if (addr_byte == 2'b01)
						wrdata = {16'b0,din[7:0],8'b0};
					else if (addr_byte == 2'b10)
						wrdata = {8'b0,din[7:0],16'b0};
					else if (addr_byte == 2'b11)
						wrdata = {din[7:0],24'b0};
					else
						wrdata = 32'b0;
				end
			`MEM_SH	:	
				begin
					if (addr_byte == 2'b00)
						wrdata = {16'b0,din[15:0]};
					else if (addr_byte == 2'b01)
						wrdata = {8'b0,din[15:0],8'b0};
					else if (addr_byte == 2'b10)
						wrdata = {din[15:0],16'b0};
					else 
						wrdata = 32'b0;
				end			
			`MEM_SW	:	wrdata = din;
			default :	wrdata = 32'b0;
		endcase
	end
	
	// load data gengrate
	
	always_comb begin
		case (mem_ctrl_pipe)
			`MEM_LB    :
				begin
					if (addr_byte_pipe == 2'b00)
						dout = {{24{rddata[7]}},rddata[7:0]};
					else if (addr_byte_pipe == 2'b01)	
						dout = {{24{rddata[15]}},rddata[15:8]};
					else if (addr_byte_pipe == 2'b10)	
						dout = {{24{rddata[23]}},rddata[23:16]};
					else if (addr_byte_pipe == 2'b11)
						dout = {{24{rddata[31]}},rddata[31:24]};	
					else
						dout = 32'b0;				
				end 
			`MEM_LH 	:
				begin
					if (addr_byte_pipe == 2'b00)
						dout = {{16{rddata[15]}},rddata[15:0]};
					else if (addr_byte_pipe == 2'b01)	
						dout = {{16{rddata[23]}},rddata[23:8]};
					else if (addr_byte_pipe == 2'b10)	
						dout = {{16{rddata[31]}},rddata[31:16]};
					else
						dout = 32'b0;				
				end 
			`MEM_LW		: dout = rddata;
			`MEM_LBU	:
				begin
					if (addr_byte_pipe == 2'b00)
						dout = {24'b0,rddata[7:0]};
					else if (addr_byte_pipe == 2'b01)	
						dout = {24'b0,rddata[15:8]};
					else if (addr_byte_pipe == 2'b10)	
						dout = {24'b0,rddata[23:16]};
					else if (addr_byte_pipe == 2'b11)
						dout = {24'b0,rddata[31:24]};
					else
						dout = 32'b0;					
				end  
			`MEM_LHU   :
				begin
					if (addr_byte_pipe == 2'b00)
						dout = {16'b0,rddata[15:0]};
					else if (addr_byte_pipe == 2'b01)	
						dout = {16'b0,rddata[23:8]};
					else if (addr_byte_pipe == 2'b10)	
						dout = {16'b0,rddata[31:16]};
					else
						dout = 32'b0;				
				end 
			default : dout = 32'b0;
		endcase
	end
	
	// inst data mem
	ram  #(
				.MEMDEEP(`DTCMDEEP)
			) inst_ram
			(
				.byteena (byteena),
				.din     (wrdata),
				.rdaddr  ({2'b00,addr[31:2]}),
				.rdclk   (clk),
				.rden    (rden),
				.wraddr  ({2'b00,addr[31:2]}),
				.wrclk   (clk),
				.wren    (wren),
				.dout    (rddata)
			);
	
endmodule
